package heap

import (
	"jvm/nzpJvm/classfile"
)

// 一个Method结构体代表一个方法的直接引用
type Method struct {
	ClassMember
	// 最大操作数栈深度
	maxStack  uint16
	// 最大本地变量表槽数
	maxLocals uint16
	// 此方法的字节码。字节码中包括操作码和操作数
	code      []byte
	// 方法参数数量
	argsSlotCount uint
}

// 根据class文件中的信息新建一个Method结构体
func newMethods(class *Class, cfMethods []*classfile.MemberInfo) []*Method {
	methods := make([]*Method, len(cfMethods))
	for i, cfMethod := range cfMethods {
		methods[i]=newMethod(class,cfMethod)
	}
	return methods
}

func newMethod(class *Class, cfMethod *classfile.MemberInfo) *Method {
	method := &Method{}
	method.class = class
	// 从class文件中复制信息和属性
	method.copyMemberInfo(cfMethod)
	method.copyAttributes(cfMethod)

	md := classfile.ParseMethodDescription(method.descriptor)
	method.calcArgsSlotCount(md.ParameterTypes)
	if method.IsNative() {
		method.injectCodeAttribute(md.ReturnType)
	}
	return method
}

// 复制属性
func (self *Method) copyAttributes(cfMethod *classfile.MemberInfo) {

	if codeAttributor := cfMethod.CodeAttributor(); codeAttributor != nil {
		self.maxStack = codeAttributor.MaxStack()
		self.maxLocals = codeAttributor.MaxLocals()
		self.code = codeAttributor.Code()
	}
}


// 当前成员能不能被指定的另一个类访问到
func (self *Method) isAccessibleTo(other *Class) bool {
	if self.IsPublic() {
		// 公开的访问权限
		return true
	}
	class := self.class
	if self.IsProtected() {
		// protected访问权限，仅限当前包下，或者其他包的子类访问
		return class == other || other.IsSubClassOf(class) || class.GetPackageName() == other.GetPackageName()
	}
	if !self.IsPrivate() {
		// 默认的访问权限，只允许当前包访问。如果是同一个类，那就一定在同一个包下
		return class.GetPackageName() == other.GetPackageName()
	}
	// 私有的访问权限，仅限当前类访问
	return class == other
}

func (self *Method) calcArgsSlotCount(ParameterTypes []string) {
	for _, paramType := range ParameterTypes {
		self.argsSlotCount++
		// long和double类型，占两个位置
		if paramType == "J" || paramType == "D" {
			self.argsSlotCount++
		}
	}
	// 此方法不是静态的，实例方法会有额外的一个参数this
	if !self.IsStatic(){
		// 实例方法会有一个额外的参数this，用于传递当前对象的引用
		self.argsSlotCount++
	}
}

// 判断访问标志
func (self *Method) IsPublic() bool {
	return 0 != self.accessFlags&ACC_PUBLIC
}
func (self *Method) IsPrivate() bool {
	return 0 != self.accessFlags&ACC_PRIVATE
}
func (self *Method) IsProtected() bool {
	return 0 != self.accessFlags&ACC_PROTECTED
}
func (self *Method) IsStatic() bool {
	return 0 != self.accessFlags&ACC_STATIC
}
func (self *Method) IsFinal() bool {
	return 0 != self.accessFlags&ACC_FINAL
}
func (self *Method) IsSynchronized() bool {
	return 0 != self.accessFlags&ACC_SYNCHRONIZED
}
func (self *Method) IsBridge() bool {
	return 0 != self.accessFlags&ACC_BRIDGE
}
func (self *Method) IsVarargs() bool {
	return 0 != self.accessFlags&ACC_VARARGS
}
func (self *Method) IsNative() bool {
	return 0 != self.accessFlags&ACC_NATIVE
}
func (self *Method) IsAbstract() bool {
	return 0 != self.accessFlags&ACC_ABSTRACT
}
func (self *Method) IsStrict() bool {
	return 0 != self.accessFlags&ACC_STRICT
}
func (self *Method) IsSynthetic() bool {
	return 0 != self.accessFlags&ACC_SYNTHETIC
}


// get
func (self *Method) MaxStack() uint {
	return uint(self.maxStack)
}
func (self *Method) MaxLocals() uint {
	return uint(self.maxLocals)
}
func (self *Method) Code() []byte {
	return self.code
}

func (self *Method) ArgsSlotCount() uint {
	return self.argsSlotCount
}

func (self *Method) injectCodeAttribute(returnType string) {
	// 注入字节码
	self.maxStack = 4
	self.maxLocals = uint16(self.argsSlotCount)
	switch returnType[0] {
	case 'V':
		self.code = []byte{0xfe,0xb1}
	case 'D':
		self.code = []byte{0xfe,0xaf}
	case 'F':
		self.code = []byte{0xfe,0xae}
	case 'J':
		self.code = []byte{0xfe,0xad}
	case 'L','[':
		self.code = []byte{0xfe,0xb0}
	default:
		self.code = []byte{0xfe,0xac}

	}
}


